package com.come4loves.game.module.fight.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;

import com.come4loves.core.result.Result;
import com.come4loves.core.utils.RandomUtils;
import com.come4loves.game.constent.GameStatusCodeConstant;
import com.come4loves.game.module.fight.action.AttackAction;
import com.come4loves.game.module.fight.action.BatchAction;
import com.come4loves.game.module.fight.action.BuffAction;
import com.come4loves.game.module.fight.action.CardToLocationAction;
import com.come4loves.game.module.fight.action.ChooseCardAction;
import com.come4loves.game.module.fight.action.MomentAction;
import com.come4loves.game.module.fight.constants.BuffType;
import com.come4loves.game.module.fight.constants.CardLocation;
import com.come4loves.game.module.fight.constants.FightConst;
import com.come4loves.game.module.fight.constants.FightMoment;
import com.come4loves.game.module.fight.constants.FighterAttribute;
import com.come4loves.game.module.fight.constants.SkillMoment;
import com.come4loves.game.module.fight.constants.Team;
import com.come4loves.game.module.fight.helper.ActionRecorder;
import com.come4loves.game.module.fight.helper.FightHelper;
import com.come4loves.game.module.fight.helper.FightPushHelper;
import com.come4loves.game.module.skill.helper.SkillHelper;
import com.come4loves.game.module.skill.model.DamageModel;

public class BattleScene {
	private Map<Long, ActorBattle> battles = new LinkedHashMap<Long, ActorBattle>();
	private boolean end = false;
	private ScheduledFuture<?> future;
	
	private int roundNum = 1;

	public BattleScene(List<ActorBattle> list) {
		for (ActorBattle actorBattle : list) {
			battles.put(actorBattle.getActorId(), actorBattle);
		}

	}

	public void getCards() {
		// 摸牌
		ActionRecorder actionRecorder = new ActionRecorder();
		for (ActorBattle actorBattle : battles.values()) {
			if (actorBattle.getFightMoment().equals(FightMoment.GET_CARD)) {
				List<FightCard> cards = actorBattle.takeCardToExpose(FightConst.INIT_HAND_CARD);
				actorBattle.setFightMoment(FightMoment.CHANGE_CARD);
				actionRecorder.addAction(new MomentAction(actorBattle.getActorId(), FightMoment.CHANGE_CARD, roundNum));
				for (FightCard fightCard : cards) {
					Card2Location card2Location = new Card2Location(fightCard, CardLocation.EXPOSE);
					CardToLocationAction cardToLocationAction = new CardToLocationAction(card2Location);
					actionRecorder.addAction(cardToLocationAction);
				}
				ChooseCardAction chooseCardAction = new ChooseCardAction(actorBattle.getActorId(), FightConst.INIT_HAND_CARD);
				actionRecorder.addAction(chooseCardAction);
			}
		}
		pushEveryOneActionRecord(actionRecorder);
	}

	public ActionRecorder changeCardMonemt(ActionRecorder actionRecorder) {
		// 切换换牌阶段
		for (ActorBattle actorBattle : battles.values()) {
			if (actorBattle.getFightMoment().equals(FightMoment.NONE)) {
				MomentAction momentAction = new MomentAction(actorBattle.getActorId(), FightMoment.CHANGE_CARD, roundNum);
				actionRecorder.addAction(momentAction);
			}
		}
		return actionRecorder;
	}

	public Collection<ActorBattle> getActorBattles() {
		return this.battles.values();
	}

	/**
	 * 出牌
	 * 
	 * @param actorId
	 * @param showCards
	 * @return
	 */
	public Result useCard(long actorId, ShowCardData showCard) {
		ActorBattle actorBattle = battles.get(actorId);

		if (actorBattle.checkCardInHand(showCard.getCardId()) == false) {
			return Result.valueOf(GameStatusCodeConstant.BATTLE_CARD_NOT_EXSIT);
		}
		if (actorBattle.checkCardMagic(showCard.getCardId()) == false) {
			return Result.valueOf(GameStatusCodeConstant.MAGIC_NOT_ENOUGH);
		}
		if (!actorBattle.getFightMoment().equals(FightMoment.USE_CARD)) {
			return Result.valueOf(GameStatusCodeConstant.NOT_IN_MONENT);
		}
		ActionRecorder actionRecorder = new ActionRecorder();
		List<FightCard> targetsCards = new ArrayList<FightCard>();
		for (int id : showCard.getTargetCardIds()) {
			FightCard card = FightHelper.serchCardInBattle(id, this.battles.values());
			if (card != null) {
				targetsCards.add(card);
			}
		}
		actorBattle.useCard(showCard.getCardId(), targetsCards, actionRecorder, this.battles.values());
		pushEveryOneUseCard(showCard,actionRecorder);
		return Result.valueOf();
	}

	/**
	 * 回合结束
	 * 
	 * @param actorId
	 */
	public void roundEnd(long actorId) {
		ActorBattle ab = battles.get(actorId);
		ab.setFightMoment(FightMoment.SHOW_CARD);
		
		for (ActorBattle actorBattle : battles.values()) {
			if (!actorBattle.getFightMoment().equals(FightMoment.SHOW_CARD) && !actorBattle.isAi()) {
				return;
			}
		}
		autoFight();
	}

	private void autoFight() {
		// 自动出牌
		allChangeCard();

		for (ActorBattle actorBattle : battles.values()) {
			ActionRecorder actionRecorder = new ActionRecorder();
			if (actorBattle.getFightMoment().equals(FightMoment.USE_CARD)) {
				if (actorBattle.getActorId() < 0) {
					actorBattle.autoUseCard(actionRecorder, this.battles.values());
				}
				actorBattle.setFightMoment(FightMoment.SHOW_CARD);
			}
			pushEveryOneActionRecord(actionRecorder);
		}
		pushEveryOneActionRecordOfMoment(FightMoment.SHOW_CARD);
		

		for (ActorBattle actorBattle : battles.values()) {
			ActionRecorder actionRecorder = new ActionRecorder();
			if (actorBattle.getFightMoment().equals(FightMoment.SHOW_CARD)) {
				actorBattle.autoShowCard(actionRecorder, this.battles.values());
				actorBattle.setFightMoment(FightMoment.ROUND_END);
			}
			pushEveryOneActionRecord(actionRecorder);
		}
		pushEveryOneActionRecordOfMoment(FightMoment.ROUND_END);
		// 结算
		for (ActorBattle actorBattle : battles.values()) {
			if (!actorBattle.getFightMoment().equals(FightMoment.ROUND_END)) {
				return;
			}
		}

		end = settlement();
		roundNum += 1;
		if (!end) {
			ActionRecorder actionRecorder = new ActionRecorder();
			BatchAction batchAction = new BatchAction();
			for (ActorBattle actorBattle : battles.values()) {
				// 回复体力
				actorBattle.fullMagic(actionRecorder);
				// 重新抓牌
				actorBattle.setFightMoment(FightMoment.GET_CARD);
				actionRecorder.addAction(new MomentAction(actorBattle.getActorId(), FightMoment.GET_CARD, roundNum));
				if (actorBattle.getFightMoment().equals(FightMoment.GET_CARD)) {
					List<FightCard> cards = actorBattle.takeCard();
					actorBattle.setFightMoment(FightMoment.USE_CARD);
					actionRecorder.addAction(new MomentAction(actorBattle.getActorId(), FightMoment.USE_CARD, roundNum));
					for (FightCard fightCard : cards) {
						Card2Location card2Location = new Card2Location(fightCard, CardLocation.HAND);
						CardToLocationAction cardToLocationAction = new CardToLocationAction(card2Location);
						actionRecorder.addAction(cardToLocationAction);
					}
				}
				actorBattle.tiggerBuff(batchAction);
				for (MainCardArea mainCardArea : actorBattle.getMainCardAreas()) {
					SkillHelper.handlerSkillModel(mainCardArea, SkillMoment.RESETPHASE, actionRecorder, actorBattle, this.battles.values(), null);
				}
			}
			actionRecorder.addAction(batchAction);

			// roundEndTime = TimeUtils.getNow();
			pushEveryOneActionRecord(actionRecorder);

		} else {
			destory();
		}
		

	}

	/**
	 * 推送动作
	 * 
	 * @param actionRecorder
	 */
	public void pushEveryOneActionRecord(ActionRecorder actionRecorder) {
		for (ActorBattle actorBattle : battles.values()) {
			FightPushHelper.pushFightActionRecorder(actorBattle.getActorId(), actionRecorder);
		}
	}
	public void pushEveryOneUseCard(ShowCardData showCardData,ActionRecorder actionRecorder) {
		for (ActorBattle actorBattle : battles.values()) {
			FightPushHelper.pushUseCard(actorBattle.getActorId(), showCardData, actionRecorder);
		}
	}

	public void pushActorActionRecord(long actorId, ActionRecorder actionRecorder) {
		FightPushHelper.pushFightActionRecorder(actorId, actionRecorder);
	}

	/**
	 * 结算
	 * 
	 * @param actionRecorder
	 * @return
	 */
	private boolean settlement() {
		
		List<ActorBattle> teamAList = new ArrayList<ActorBattle>();
		List<ActorBattle> teamBList = new ArrayList<ActorBattle>();
		
		for (ActorBattle actorBattle : battles.values()) {
			if (actorBattle.getTeam().equals(Team.TEAM_A)) {
				teamAList.add(actorBattle);
			} else {
				teamBList.add(actorBattle);
			}
		}
		
		//TEAM_A 出手
		for (ActorBattle actorBattle : teamAList) {
			ActorBattle firstBattle = actorBattle;
			ActorBattle secondBattle = teamBList.get(RandomUtils.nextIntIndex(teamBList.size()));
			doSettlement(firstBattle, secondBattle);
		}
		//TEMA_B出手
		for (ActorBattle actorBattle : teamBList) {
			ActorBattle firstBattle = actorBattle;
			ActorBattle secondBattle = teamAList.get(RandomUtils.nextIntIndex(teamAList.size()));
			doSettlement(firstBattle, secondBattle);
		}
		
		
		
		
		

//		boolean flag = true;
//		AttackListModel attackListModel1 = new AttackListModel(firstBattle);
//		AttackListModel attackListModel2 = new AttackListModel(secondBattle);
//
//		AttackListModel attakerList = null;
//		AttackListModel beAttakerList = null;
//		while (true) {
//
//			if (flag) {
//				attakerList = attackListModel1;
//				beAttakerList = attackListModel2;
//			} else {
//				attakerList = attackListModel2;
//				beAttakerList = attackListModel1;
//			}
//			flag = flag ? false : true;
//			this.offensiveTeam = this.offensiveTeam.equals(Team.TEAM_A) ? Team.TEAM_B : Team.TEAM_A;
//			if (attakerList.handComplete() && beAttakerList.handComplete()) {
//				break;
//			}
//			if (attakerList.isAllDead() || beAttakerList.isAllDead()) {
//				end = true;
//				break;
//			}
//			if (attakerList.handComplete())
//				continue;
//			// 调试信息
//
//			FightCard attacker = attakerList.hand();
//			if (attacker == null) {
//				break;
//			}
//			doFight(attacker, attakerList.getActorBattle(), beAttakerList.getActorBattle(), actionRecorder, attakerList.getChooseTarget(attacker));
//
//		}
//		pushEveryOneActionRecord(actionRecorder);
//		firstBattle.handleDead();
//		secondBattle.handleDead();
//		firstBattle.getCurrentTarget().clear();
//		secondBattle.getCurrentTarget().clear();
		return end;

	}
	/**
	 * 单次结算
	 * @param firstBattle
	 * @param secondBattle
	 */
	private void doSettlement(ActorBattle firstBattle, ActorBattle secondBattle) {
		ActionRecorder actionRecorder = new ActionRecorder();
		AttackListModel attakerList = new AttackListModel(firstBattle);
		AttackListModel beAttakerList = new AttackListModel(secondBattle);

		while (true) {
			if (attakerList.isAllDead() || beAttakerList.isAllDead()) {
				end = true;
				break;
			}
			if (attakerList.handComplete())
				break;

			FightCard attacker = attakerList.hand();
			if (attacker == null) {
				break;
			}
			doFight(attacker, attakerList.getActorBattle(), beAttakerList.getActorBattle(), actionRecorder, attakerList.getChooseTarget(attacker));

		}
		pushEveryOneActionRecord(actionRecorder);
		firstBattle.handleDead();
		secondBattle.handleDead();
		firstBattle.getCurrentTarget().clear();
		secondBattle.getCurrentTarget().clear();
	}

	private void doFight(FightCard attacker,ActorBattle actorBattle,ActorBattle beActorBattle, ActionRecorder actionRecorder, List<FightCard> chooseTarget) {
		List<FightCard> targets = null;
		if (attacker.isBuffAble(BuffType.WINDFURY)) {
			for (int i = 0; i < 2; i++) {
				if (chooseTarget != null && !chooseTarget.isEmpty()) {
					targets = chooseTarget;
				} else {
					targets = getTargets(attacker, beActorBattle.getMainCards(), beActorBattle.getShowCards().values());
				}
				if (targets.size() == 0) {
					return;
				}
				onceAttack(attacker, actorBattle,beActorBattle, targets, actionRecorder, chooseTarget);
				if (attacker.isDead()) {
					break;
				}
			}
		} else {
			if (chooseTarget != null && !chooseTarget.isEmpty()) {
				targets = chooseTarget;
			} else {
				targets = getTargets(attacker, beActorBattle.getMainCards(), beActorBattle.getShowCards().values());
			}
			if (targets.size() == 0) {
				return;
			}
			onceAttack(attacker, actorBattle,beActorBattle ,targets, actionRecorder,chooseTarget);
		}
	}

	private void onceAttack(FightCard attacker,ActorBattle actorBattle,ActorBattle beActorBattle, List<FightCard> targets, ActionRecorder actionRecorder, List<FightCard> chooseTarget) {
		for (FightCard fightCard : targets) {
			AttackAction action = new AttackAction(attacker.getId(), fightCard.getId());
			actionRecorder.addAction(action);
			if (attacker.isGenenral()) {//主将攻击时
				SkillHelper.handlerSkillModel(actorBattle.getMainCardArea(attacker), SkillMoment.EQUIPGENERALATTCAK, actionRecorder, actorBattle, this.battles.values(), chooseTarget);
			}
			if (fightCard.isGenenral()) {//主将受到攻击时
				SkillHelper.handlerSkillModel(beActorBattle.getMainCardArea(fightCard), SkillMoment.EQUIPGENERALDEFENSE, actionRecorder, actorBattle, this.battles.values(), chooseTarget);
			}
			DamageModel damageModel = FightHelper.realDamage(fightCard, attacker.getAttack(), true,actionRecorder);
			action.putBeAttackValue(FighterAttribute.HP, damageModel.getRealDamage(), false);
			if (damageModel.getRealDamage() > 0) {
				if (attacker.isGenenral()) {//主将造成伤害时
					SkillHelper.handlerSkillModel(actorBattle.getMainCardArea(attacker), SkillMoment.EQUIPGENERALHALTDAMAGE, actionRecorder, actorBattle, this.battles.values(), chooseTarget);
				}
				if (fightCard.isGenenral()) {//主将受到伤害时
					SkillHelper.handlerSkillModel(beActorBattle.getMainCardArea(fightCard), SkillMoment.EQUIPGENERALDEALDAMAGE, actionRecorder, actorBattle, this.battles.values(), chooseTarget);
				}
			}
			damageModel = FightHelper.realDamage(attacker, fightCard.getAttack(), true, actionRecorder);
			action.putAttackValue(FighterAttribute.HP, damageModel.getRealDamage(), false);
			if (damageModel.getRealDamage() > 0) {
				if (fightCard.isGenenral()) {//主将造成伤害时
					SkillHelper.handlerSkillModel(beActorBattle.getMainCardArea(fightCard), SkillMoment.EQUIPGENERALHALTDAMAGE, actionRecorder, actorBattle, this.battles.values(), chooseTarget);
				}
				if (attacker.isGenenral()) {//主将受到伤害时
					SkillHelper.handlerSkillModel(actorBattle.getMainCardArea(attacker), SkillMoment.EQUIPGENERALDEALDAMAGE, actionRecorder, actorBattle, this.battles.values(), chooseTarget);
				}
			}

			action.setCurrentAttackerHP(attacker.getHp());
			action.setCurrentBeAttackerHP(fightCard.getHp());
			

			if (attacker.isBuffAble(BuffType.HIDDEN)) {
				List<BuffData> list = attacker.removeBuff(BuffType.HIDDEN);
				for (BuffData buffData : list) {
					BuffAction buffAction = new BuffAction(attacker, buffData, 0);
					actionRecorder.addAction(buffAction);
				}
			}

			BatchAction batchAction = new BatchAction();
			if (attacker.isDead()) {
				FightHelper.createDeadAction(attacker, batchAction);
				SkillHelper.handlerSkillModel(attacker, SkillMoment.UNITLEFTED, actionRecorder, FightHelper.getActorBattle(attacker,this.battles.values()), this.battles.values(), null);
			}
			if (fightCard.isDead()) {
				FightHelper.createDeadAction(fightCard, batchAction);
				SkillHelper.handlerSkillModel(fightCard, SkillMoment.UNITLEFTED, actionRecorder, FightHelper.getActorBattle(fightCard, this.battles.values()), this.battles.values(), null);
			}
			
			
			
			actionRecorder.addAction(batchAction);

			if (attacker.isDead()) {
				break;
			}
		}
	}

	private List<FightCard> getTargets(FightCard attacker, Collection<FightCard> beAttackerMainCard, Collection<FightCard> beAttackerList) {
		List<FightCard> allBeAttackCards = new ArrayList<FightCard>();
		allBeAttackCards.addAll(beAttackerMainCard);
		allBeAttackCards.addAll(beAttackerList);
		List<FightCard> list = new ArrayList<FightCard>();
		for (FightCard fightCard : allBeAttackCards) {
			if (!fightCard.isDead() && !fightCard.isBuffAble(BuffType.HIDDEN)) {
				list.add(fightCard);
			}
		}
		List<FightCard> listTaunt = new ArrayList<FightCard>();
		for (FightCard fightCard : list) {
			if (fightCard.isBuffAble(BuffType.TAUNT)) {
				listTaunt.add(fightCard);
			}
		}
		if (!listTaunt.isEmpty()) {
			list = listTaunt;
		}
		// 随机一个活着的卡牌
		if (list.size() <= 1) {
			return list;
		}
		List<FightCard> result = new ArrayList<FightCard>();
		result.add(list.get(RandomUtils.nextIntIndex(list.size())));
		return result;
	}

	public void destory() {
		if (this.future != null) {
			this.future.cancel(true);
		}
	}

	public boolean isEnd() {
		return end;
	}


	/**
	 * 换牌
	 * 
	 * @param actorId
	 * @param idList
	 * @return
	 */
	public Result changeCard(long actorId, List<Integer> idList) {
		ActorBattle actorBattle = battles.get(actorId);

		for (int id : idList) {
			if (actorBattle.checkCardInExpose(id) == false) {
				return Result.valueOf(GameStatusCodeConstant.BATTLE_CARD_NOT_EXSIT);
			}
			if (!actorBattle.getFightMoment().equals(FightMoment.CHANGE_CARD)) {
				return Result.valueOf(GameStatusCodeConstant.NOT_IN_MONENT);
			}
		}
		ActionRecorder actionRecorder = new ActionRecorder();
		actorBattle.changeCard(idList, actionRecorder, this.roundNum);
		pushEveryOneActionRecord(actionRecorder);

		//电脑自动换牌
		allChangeCard();
		return Result.valueOf();
	}


	/**
	 * 所有人自动换牌
	 */
	private void allChangeCard() {
		ActionRecorder actionRecorder = new ActionRecorder();
		for (ActorBattle actorBattle : battles.values()) {
			if (actorBattle.getFightMoment().equals(FightMoment.CHANGE_CARD)) {
				if (actorBattle.getActorId() < 0) {
					actorBattle.changeCard(new ArrayList<Integer>(), actionRecorder, this.roundNum);
					actorBattle.setFightMoment(FightMoment.USE_CARD);
					actionRecorder.addAction(new MomentAction(actorBattle.getActorId(), FightMoment.USE_CARD, this.roundNum));
				}
			}
		}
		pushEveryOneActionRecord(actionRecorder);
	}
	
	private void pushEveryOneActionRecordOfMoment(FightMoment fightMoment) {
		ActionRecorder actionRecorder = new ActionRecorder();
		actionRecorder.addAction(new MomentAction(0, fightMoment, this.roundNum));
		pushEveryOneActionRecord(actionRecorder);
	}

	
}
